﻿#include "Tool.h"
#pragma warning(disable : 4996)

class logEnum
{
public:
	static logEnum& Init();

	//注销器
	template<typename EnumT>
	void logoutDevice();

	//注册
	template<typename EnumT>
	void registerDevice(const std::function<std::string(EnumT)>& infor);

	template<typename EnumT>
	std::string toString(const EnumT& other);

private:
	std::unordered_map<std::type_index, std::function<std::string(int)>> _typeToString;

};

class logMsg
{
public:
	logMsg();

	logMsg(const std::string& data, int level, const std::string& loggerName, const std::string& fileName, size_t line);

	void clear();

	void insert(const std::string& data, int level, const std::string& loggerName, const std::string& fileName, size_t line);

public:
	size_t _time;

	std::thread::id _id;

	size_t _line;

	int _level;

	std::string _fileName;

	std::string _data;

	std::string _loggerName;
};

class logFormat
{
public:
	logFormat() = default;

	void insert( const std::string& key, const std::function<std::string(logMsg)>& fun);

	void clear();

	std::function<std::string(logMsg)> get(const std::string& key);

private:
	std::unordered_map<std::string, std::function<std::string(logMsg)>> _formatFunMap;
};

//提供一个接口, 传入一个消息类，格式化输出一个消息字符串, 格式由最开始提供
class Reformat
{
public:
/* 默认 %d⽇期         
		%T缩进         
		%t线程id
		%p⽇志级别
		%c⽇志器名称
		%f⽂件名
		%l⾏号
		%m⽇志消息
		%n换⾏                      *//*日志器需要将这个类包一下*/
	Reformat(const std::string& pattern = "[%d][%t][%p][%c][%f:%l] %m %n");

	void setPattern(const std::string& logFormat);

	//提供给上层
	void change(const std::string& key, const std::function<std::string(logMsg)>& fun);

	void clear();

	std::string format(const logMsg& log);

private:
	logFormat _logFormat;

	std::vector<std::string> _pattern;
};

template<typename EnumT>
inline void logEnum::logoutDevice()
{
	auto it = _typeToString.find(typeid(EnumT));
	if (it != _typeToString.end())
	{
		_typeToString.erase(it);
	}
}

template<typename EnumT>
inline void logEnum::registerDevice(const std::function<std::string(EnumT)>& infor)
{
	_typeToString[typeid(EnumT)] = [infor](int value)
		{
			return infor(static_cast<EnumT>(value));
		};
}

template<typename EnumT>
inline std::string logEnum::toString(const EnumT& other)
{
	auto it = _typeToString.find(typeid(EnumT));
	if (it != _typeToString.end())
	{
		return it->second(static_cast<int>(other));
	}
	return "";
}

//默认枚举
enum class Level : uint8_t
{
	ALL = 0,
	DEBUG,
	INFO,
	WARN,
	ERROR,
	FATAL,
	OFF
};

